package com.anc.web.filter;

import com.anc.web.constants.WebHandleConfigConstants;
import com.anc.web.filter.log.LogPatternConfig;
import com.anc.web.util.LogUtil;
import com.anc.web.wrapper.WrappedHttpServletRequest;
import com.anc.web.wrapper.WrappedHttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import static constants.CommonConstants.LINE_SEP;


/**
 * 记录请求响应log
 * 过滤健康健康url /actuator/health
 *
 * @author Anc
 * @date 2022/7/01
 */
public class LogFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(LogFilter.class);

    private static Set<String> defaultNotLogUrlPatternSet = new HashSet<>(
        // 默认排除健康检查
        Collections.singletonList("/actuator/health")
    );

    private LogPatternConfig logPatternConfig;

    public LogFilter() {
        this.logPatternConfig = LogPatternConfig.builder()
            .requestLengthLimit(WebHandleConfigConstants.REQUEST_PRINT_THRESHOLD)
            .responseLengthLimit(WebHandleConfigConstants.RESPONSE_PRINT_THRESHOLD)
            // 设置默认的
            .notLogUrlPatternSet(defaultNotLogUrlPatternSet)
            .build();
    }

    public LogFilter(LogPatternConfig logPatternConfig) {
        this(logPatternConfig,true);
    }

    public LogFilter(LogPatternConfig logPatternConfig,boolean hasDefaultNotUrlPattern) {
        // 设置默认值
        if(logPatternConfig.getNotLogUrlPatternSet() == null){
            logPatternConfig.setNotLogUrlPatternSet(new HashSet<>());
        }
        if(logPatternConfig.getRequestLengthLimit() <= 0){
            logPatternConfig.setRequestLengthLimit(WebHandleConfigConstants.REQUEST_PRINT_THRESHOLD);
        }
        if(logPatternConfig.getResponseLengthLimit() <= 0){
            logPatternConfig.setResponseLengthLimit(WebHandleConfigConstants.RESPONSE_PRINT_THRESHOLD);
        }

        if(hasDefaultNotUrlPattern){
            // 将默认的不打印日志的请求路径加入
            logPatternConfig.getNotLogUrlPatternSet().addAll(defaultNotLogUrlPatternSet);
        }

        this.logPatternConfig = logPatternConfig;
    }


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // response wrapper
        WrappedHttpServletResponse httpServletResponse = new WrappedHttpServletResponse((HttpServletResponse) response);
        //request wrapper
        HttpServletRequest httpServletRequest = new WrappedHttpServletRequest((HttpServletRequest) request);
        StringBuilder requestInfoBuilder = new StringBuilder();

        // 收集 request uri, header
        if (needPrintLog(httpServletRequest.getRequestURI())) {
            LogUtil.collectBaseInfo(httpServletRequest, requestInfoBuilder);
            long requestStartAt = System.currentTimeMillis();
            try {
                chain.doFilter(httpServletRequest, httpServletResponse);
            } finally {
                String responseContent = httpServletResponse.getResponseContent();
                final long requestEndTime = System.currentTimeMillis();
                long cost = requestEndTime - requestStartAt;

                String requestPrintStr;
                if(requestInfoBuilder.length() > this.logPatternConfig.getRequestLengthLimit()){
                    requestPrintStr = "";
                }else{
                    requestPrintStr = requestInfoBuilder.toString();
                }
                String responsePrintStr;
                if(responseContent.length() > this.logPatternConfig.getResponseLengthLimit()){
                    responsePrintStr = "";
                }else{
                    responsePrintStr = responseContent;
                }

                logger.info("{}{} cost time: {} ms {} response info: {}{}",
                    requestPrintStr, LINE_SEP,
                    cost, LINE_SEP,
                    responsePrintStr, LINE_SEP);
            }
        }else{
            // 直接放过去
            chain.doFilter(httpServletRequest, httpServletResponse);
        }


    }

    @Override
    public void destroy() {

    }

    private boolean needPrintLog(String url){
        for(String notLogUrlItem : this.logPatternConfig.getNotLogUrlPatternSet()){
            // 在名单中的url，将其排除掉
            if(url.contains(notLogUrlItem)){
                return false;
            }
        }

        return true;
    }
}
